package com.starleague.common;

import java.util.Collection;
import java.util.Map;

public abstract class AbstractChildVisitor
        implements IChildVisitor
{
    @Override
    public <KEY, VALUE> void visit(KEY key,
                                   VALUE value)
    {
        if (value instanceof IChildVisitable)
        {
            visitChildVisitable(key, (IChildVisitable) value);
        }
        else if (value instanceof Collection)
        {
            visitCollection(key, (Collection<?>) value);
        }
        else if (value instanceof Object[])
        {
            visitArray(key, (Object[]) value);
        }
        else if (value instanceof Map)
        {
            visitMap(key, (Map<?, ?>) value);
        }
        else
        {
            visitValue(key, value);
        }
    }

    protected abstract <KEY, VALUE> void visitValue(KEY key,
                                                    VALUE value);

    protected <KEY> void visitChildVisitable(KEY key,
                                             IChildVisitable visitable)
    {
        visitable.accept(this);
    }

    protected <KEY, VALUE> void visitCollection(KEY key,
                                                Collection<? extends VALUE> collection)
    {
        int index = 0;
        for (VALUE value : collection)
            visit(Integer.valueOf(index++), value);

    }

    protected <KEY, VALUE> void visitArray(KEY key,
                                           VALUE[] array)
    {
        for (int index = 0; index < array.length; ++index)
            visit(Integer.valueOf(index), array[index]);
    }

    protected <KEY, MAPKEY, MAPVALUE> void visitMap(KEY key,
                                                    Map<? extends MAPKEY, ? extends MAPVALUE> map)
    {
        for (Map.Entry<? extends MAPKEY, ? extends MAPVALUE> entry : map.entrySet())
            visit(entry.getKey(), entry.getValue());
    }
}
